﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Security.Cryptography;
using System.IO;

/* C# Symmetric key encryption (also known as secret-key encryption), is a cryptographic technique that uses a single secret key to encrypt and decrypt data. 
 * The methods within symmetric encryption are also known as “ciphers”, and process plain text using the secret key to generate encrypted data, called “cipher text”.
 * 
 * Symmetric algorithms are fast and are convenient when encrypting large amounts of data. 
 * Decrypting the data without the key can take an attacker hundreds of years (if a proper key length is used).
 * 
 * The disadvantage of this technique is that the secret key must be available to both the process that encrypts the data and the process that decrypts the data. 
 * This is a challenging problem because the key itself cannot be protected with symmetric encryption.
 * The secure way to exchange the symmetric key is to encrypt it asymmetrically.
 */
namespace VMCCryptoLib.SymmetricEncryption
{
	/// <summary>
	/// Class to do an encryptor with DES algorithm.
	/// 
	/// The Data Encryption Standard (DES) is a secret key encryption scheme adopted as standard in the USA in 1977. 
	/// It uses a 56-bit key, which is today considered by many to be insufficient as it can with moderate effort be cracked by brute force. 
	/// A variant called Triple-DES (TDES or 3DES) uses a longer key and is more secure, but has never become popular. 
	/// The Advanced Encryption Standard (AES) is expected to supersede DES (and 3DES) as the standard encryption algorithm.
	/// 
	/// This secret key encryption algorithm uses a key that is 56 bits, or seven characters long. 
	/// At the time it was believed that trying out all 72,057,594,037,927,936 possible keys (a seven with 16 zeros) would be impossible because computers could not possibly ever become fast enough. 
	/// In 1998 the Electronic Frontier Foundation (EFF) built a special-purpose machine that could decrypt a message by trying out all possible keys in less than three days. 
	/// The machine cost less than $250,000 and searched over 88 billion keys per second.
	/// </summary>
    public class DESEncryption
    {
    	#region --- Method to encrypt and decrypt a file
    	public static bool DecryptFile(string fileToDecrypt, string destination, string password)
    	{
    		bool rs = false;
    		try
    		{
    			FileStream fin = new FileStream(fileToDecrypt, FileMode.Open, FileAccess.Read);
    			FileStream fout = new FileStream(destination, FileMode.OpenOrCreate, FileAccess.ReadWrite);
    			
    			PasswordDeriveBytes pdb = new PasswordDeriveBytes(password, new byte[]  {0x49, 0x76, 0x61, 0x6e, 0x20, 0x4d, 0x65, 0x64, 0x76, 0x65, 0x64, 0x65, 0x76});
    			DES algo = DES.Create();
    			algo.Key = pdb.GetBytes(32);
    			algo.IV = pdb.GetBytes(16);
    			
    			byte[] fileData = new byte[fin.Length];
    			ICryptoTransform crypto = algo.CreateDecryptor();
    			
    			CryptoStream crpStream = new CryptoStream(fout,crypto, CryptoStreamMode.Write);
    			crpStream.Write(fileData,0,fileData.Length);
    			
    			rs = true;
    			
    			crpStream.Close();
    			fin.Close();
    			fout.Close();
    			
    		}
    		catch(Exception ex)
    		{
    			return rs;
    			throw new Exception(ex.Message);
    		}
    		return rs;
    	}
    	
    	public static bool EncryptFile(string fileToEncrypt, string destination, string password)
    	{
    		bool rs =false;
    		if(fileToEncrypt!= null || fileToEncrypt.Length!=0 || destination!= null || destination.Length!=0)
    		{
    			try
    			{
    				FileStream fin = new FileStream(fileToEncrypt, FileMode.Open, FileAccess.Read);
    				FileStream fout = new FileStream(destination, FileMode.OpenOrCreate, FileAccess.ReadWrite);
    				
    				// Then we are going to derive a Key and an IV from the
                	// Password and create an algorithm 
                	PasswordDeriveBytes pdb = new PasswordDeriveBytes(password, new byte[] {0x49, 0x76, 0x61, 0x6e, 0x20, 0x4d, 0x65, 0x64, 0x76, 0x65, 0x64, 0x65, 0x76});
                	DES algo = DES.Create();
                	algo.Key = pdb.GetBytes(32);
                	algo.IV = pdb.GetBytes(16);
                	
                	byte[] fileData = new byte[fin.Length];
                	
                	ICryptoTransform crypto = algo.CreateEncryptor();
                	
                	CryptoStream crpStream = new CryptoStream(fout, crypto, CryptoStreamMode.Write);
                	crpStream.Write(fileData,0,fileData.Length);
                	
                	rs = true; // return a result if encrypt proccessing is success
                	
                	crpStream.Close();
                	fin.Close();
                	fout.Close();
    			}
    			catch(Exception ex)
    			{
    				rs = false;
    				throw new Exception(ex.Message);
    			}
    		}else
    		{
    			rs = false;
    		}
    		return rs;
    	}
    	#endregion
    	
    	#region --- Methods to encrypt and decrypt a string
        /// <summary>
        /// Method to encrypt a string with DES encryption
        /// </summary>
        /// <param name="input">a string to encrypt</param>
        /// <returns>encrypted string</returns>
        public static string EncrypString(string inputData, string password)
        {
            string rs = string.Empty;
            
            if(rs!= null || rs.Length !=0)
            {
				try
				{
					byte[] clearBytes = Encoding.Unicode.GetBytes(inputData);
					PasswordDeriveBytes pdb = new PasswordDeriveBytes(password, new byte[] {0x49, 0x76, 0x61, 0x6e, 0x20, 0x4d, 0x65, 0x64, 0x76, 0x65, 0x64, 0x65, 0x76});
					byte[] encryptData = DESEncrypt(clearBytes,pdb.GetBytes(32),pdb.GetBytes(16));
					rs = Convert.ToBase64String(encryptData);
				}
				catch(Exception ex)
				{
					rs = ex.Message;
				}
            }
            else
            {
            	rs = string.Empty;
            }
            
            return rs;
        }

        /// <summary>
        /// Method to descrypt tring with DES
        /// </summary>
        /// <param name="input">a string encrypted</param>
        /// <returns>decrypted string</returns>
        public static string DescryptString(string cipherData, string password)
        {
            string rs = string.Empty;
            if(rs!=null || rs.Length!=0)
            {
				try
				{
					byte[] cipherBytes = Convert.FromBase64String(cipherData);
					PasswordDeriveBytes pdb = new PasswordDeriveBytes(password, new byte[] {0x49, 0x76, 0x61, 0x6e, 0x20, 0x4d, 0x65, 0x64, 0x76, 0x65, 0x64, 0x65, 0x76});
					byte[] decryptData = DESDecrypt(cipherBytes,pdb.GetBytes(32),pdb.GetBytes(16));
					rs = Encoding.Unicode.GetString(decryptData);
				}
				catch(Exception ex)
				{
					rs = ex.Message;
				}
           	}
            else
            {
            	rs = string.Empty;
            }
            return rs;
        }
        #endregion ---
        
        #region --- Private methods
        private static byte[] DESEncrypt(byte[] clearData, byte[]Key, byte[] IV)
        {
        	MemoryStream memoStream = new MemoryStream(); // Hold encrypted data
        	DES alg = DES.Create(); // Create a instance of cryptography object
        	alg.Key = Key;
        	alg.IV = IV;
        	CryptoStream crpStream = new CryptoStream(memoStream,alg.CreateEncryptor(),CryptoStreamMode.Write);
        	crpStream.Write(clearData,0,clearData.Length);
        	crpStream.Close(); // Close CryptoStream, it's mean no more data is coming
        	byte[] encryptedData = memoStream.ToArray(); // get encrypted from memory
        	return encryptedData;
       	}
        
        private static byte[] DESDecrypt(byte[] cipherData, byte[] Key, byte[] IV)
        {
        	MemoryStream memoStream = new MemoryStream();
        	DES alg = DES.Create();
        	alg.Key=Key;
        	alg.IV=IV;
        	CryptoStream crpStream = new CryptoStream(memoStream, alg.CreateDecryptor(), CryptoStreamMode.Write);
        	crpStream.Write(cipherData,0,cipherData.Length);
        	crpStream.Close();
        	byte[] decryptedData = memoStream.ToArray();
        	return decryptedData;
        }
        #endregion
    }
}
